<!doctype html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>磁强计</title>
  <link rel="stylesheet" href="/static/css/bootstrap.min.css">
  <link rel="stylesheet" href="/omsp/qv.css">
  <link rel="stylesheet" href="/omsp/qv-table.css">
  <script src="/static/js/jquery-3.6.0.min.js"></script>
  <script src="/static/js/echarts.5.5.js"></script>
  <script src="/static/js/echarts-gl.min.js"></script>
  <script src="/static/js/xtool.js?12"></script>
  <script src="/omsp/qv.js"></script>
  <style>
    th {
      width: 150px;
    }
  </style>
</head>
<body class="real-panel">
<div class="d-flex flex-row bg-transparent" style="height: calc(100vh);">
  <div class="d-flex flex-grow-1 flex-column position-relative border">
    <div class="real pt-1 ps-3  pe-2">
      <button id="r-history" class="btn btn-primary btn-sm " onclick="pg.history()">历史</button>
      <button class="btn btn-primary btn-sm" onclick="pg.download()">下载</button>
      <label id="r-task" class="ps-3"></label>
    </div>
    <div class="history pt-1 ps-3  pe-2 d-flex flex-column">
      <div>
        <button id="h-real" class="btn btn-primary btn-sm " onclick="pg.realtime()">实时</button>
        <label class="ps-3">日期: <input type="date" id="h-t" onchange="pg.changeDay()"></label>
        <label class="ps-3">任务: <select id="h-tasks" class="form-select-sm" style="min-width: 120px"
                                        onchange="pg.changeTask()"></select></label>
        <label>最大帧数：<span id="frm-max"></span></label>
        <label class="ps-3">帧号：
          <input type="number" id="frm-num" min="1" max="1" onchange="pg.changeFrmNum()">
          <input type="range" min="1" max='1' id="frm-range" onchange="pg.changeFrmRange()"/>
        </label>
      </div>
      <div class="pt-2">
        <button class="btn btn-primary btn-sm" onclick="pg.download()">下载</button>
        <label class="ps-3">时间(UTC+8):
          <input type="datetime-local" id="h-start">~ <input type="datetime-local" id="h-end">
        </label>
        <label class="ps-3">组抽样(0~60)：<input type="number" min="0" max="60" id="sample-grp"/></label>
        <label class="ps-3">帧抽样：<input type="number" id="sample-frm"/></label>
        <button class="btn btn-primary btn-sm" onclick="pg.sample()">抽样</button>
      </div>
      <div class="pt-2">

      </div>
    </div>
    <div class="flex-grow-1 py-3 d-grid " style="grid-template-columns: auto auto;align-content: stretch;">
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
    </div>
  </div>
  <div class="d-flex flex-column border xinfo-panel1">
    <div class="bg-primary opacity-75 ps-1 py-1 text-white">科学数据信息</div>
    <div class="flex-grow-1 position-relative">
      <div class="position-absolute h-100 w-100 xbg-panel1">
        <table class="table table-bordered table-hover table-sm small">
          <tbody id="info">

          </tbody>
        </table>
      </div>
    </div>
  </div>
</div>
</body>
<script>
  var $INFO;
  var COLOR = ['red', 'green', 'blue']
  var ws
  var charts

  class Page extends Realtime {
    constructor() {
      super('AMAG', $STATION || 'GRAS4')
      // let dim = ['x', 'ax', 'ay', 'az', 'bx', 'by', 'bz']
      this.dim = ['x', 'y', null, null, null, null, null]
      $INFO = $('#info')
      this.deffrm = 1
      this.fmin = this.deffrm
      this.fmax = this.deffrm
      let chartBox = Array.from(document.querySelectorAll('.chart'));
      charts = chartBox.map((v, i) => {
        let c = echarts.init(v)
        c.setOption(this.genOption(i))
        return c
      });
    }

    download() {
      if (!this.cur_task) return
      let parms = this.task
      let filename = `${parms.st}-${parms.orb}-${$INS}.h5`
      let url = `/-/omsp.downf?f=${this.task}`
      downFile(url, filename)
    }

    changeFrmNum() {
      let frmid = $('#frm-num').val()
      this.frm = this.normalFrmId(frmid)
      $('#frm-range').val(this.frm)
      $('#frm-num').val(this.frm)
      // $('#frm-cur').text(this.frm)
      this.clearFrmDisplay()
      this.loadFrm()
    }

    normalFrmId(frmid) {
      let v = parseInt(frmid)
      if (v > this.fmax) v = this.fmax
      if (v < this.fmin) v = this.fmin
      return v
    }

    async changeTask() {
      this.clearTask()
      this.task = $('#h-tasks').val()
      if (this.task == '') return
      await this.loadTask()
      await this.loadFrm()
    }

    changeFrmRange() {
      let frmid = $('#frm-range').val()
      this.frm = this.normalFrmId(frmid)
      $('#frm-num').val(this.frm)
      // $('#frm-cur').text(this.frm)
      this.clearFrmDisplay()
      this.loadFrm()
    }


    genOption(i) {
      let A = 'XYZ'
      let B = 'AB'
      let title = `探头${B[i % 2]} ${A[parseInt(i / 2)]}轴磁场`;
      let dimIdx = (i % 2) * 3 + parseInt(i / 2) + 1
      return {
        title: {text: title, textStyle: {fontSize: 12}, left: 'center'},
        color: [COLOR[parseInt(i / 2)]],
        grid: {left: 100, top: 40, bottom: 30, right: 30},
        animation: false,
        dataZoom: [{type: 'inside', start: 0, end: 100}],
        tooltip: {trigger: 'axis'}, xAxis: {type: 'time'}, yAxis: {name: 'nT', axisLine: {show: true}, scale: true},
        series: [{
          type: 'line', showSymbol: false, symbol: 'none', dimensions: this.dim, encode: {
            x: 0,
            y: dimIdx
          }, lineStyle: {width: 1}, data: []
        }]
      }
    }

    realtime() {
      super.realtime()
      this.body.classList = 'real-panel'
      $('#r-task').html('')
      this.clearFrmAll()
      this.resize();
    }

    async history() {
      super.history()
      $REAL_FLAG = false
      this.body.classList = 'his-panel'
      this.clearAll()
      this.resize()
    }

    clearAll() {
      $('#h-tasks').html('')
      this.clearTask()
    }

    clearTask() {
      this.task = ''
      $('#h-start').val('')
      $('#h-end').val('')
      $('#sample-frm').val('')
      $('#sample-grp').val('')
      this.clearFrmAll()
    }

    clearFrmAll() {
      this.clearFrmInput()
      this.clearFrmDisplay()
    }

    clearFrmDisplay() {
      $INFO.html('')
      this.clearChartData()
    }

    clearFrmInput() {
      let defv = 1
      this.frm = ''
      $('#frm-range').attr({min: defv, max: defv})
      $('#frm-num').attr({min: defv, max: defv})
      $('#frm-num').val(this.frm)
      $('#h-start').val('')
      $('#h-end').val('')
      // $('#frm-cur').text(this.frm)
      $('#frm-max').text('')
    }

    async loadTask() {
      if (this.task == '' || this.task == null) return
      let resp = await fetch(`/-/omsp.amag.taskInfo?task=${this.task}`).then(r => r.json())
      if (resp.fmin != undefined) {
        this.frm = resp.fmin
        this.fmax = resp.fmax
        this.fmin = resp.fmin
        $('#frm-range').attr({min: this.fmin, max: this.fmax})
        $('#frm-num').attr({min: this.fmin, max: this.fmax})
        $('#frm-num').val(this.frm)
        $('#h-start').val(resp.tstart.slice(0, 19))
        $('#h-end').val(resp.tend.slice(0, 19))
        // $('#frm-cur').text(this.frm)
        $('#frm-max').text(this.fmax)
      }
    }

    async loadFrm() {
      if (this.task == undefined || this.task === '' || this.task == null) return
      if (this.frm == undefined || this.frm === '' || this.frm == null) return

      let resp = fetch(`/-/omsp.amag.frmdata?task=${this.task}&frm=${this.frm}`)
      let frmInfo = await $api(`omsp.amag.frminfo?task=${this.task}&frm=${this.frm}`)
      let rp = await resp
      if (rp.ok) {
        let buf = await rp.arrayBuffer()
        this.renderBuf(buf)
        set_frmInfo(frmInfo)
      }

    }

    renderBuf(buf) {
      let arr = new Float64Array(buf, 0, buf.byteLength / Float64Array.BYTES_PER_ELEMENT);
      charts.forEach((c, i) => {
        c.setOption({series: {data: arr}})
      })
    }

    async sample() {
      let start = $('#h-start').val()
      let end = $('#h-end').val()
      let ifrm = $('#sample-frm').val()
      let igrp = $('#sample-grp').val()
      if (!(ifrm || igrp)) return
      this.clearChartData()
      charts[0].showLoading()
      try {
        let buf = await $api(
          `omsp.amag.sample?task=${this.task}&igrp=${igrp}&ifrm=${ifrm}&s=${start}&e=${end}`,
          null, (v) => v.arrayBuffer(), v => alert('ERROR')
        )
        this.renderBuf(buf)
      } finally {
        charts[0].hideLoading()
      }

    }

    clearChartData() {
      charts.forEach((v, i) => {
        v.clear();
        v.setOption(this.genOption(i))
      });
    }

    resize() {
      charts.forEach(v => v.resize());
    }
  }

  let pg
  window.onload = () => {
    $INS = 'AMAG'
    pg = new Page()
    pg.real()
    window.onresize = pg.resize
  }

  let ST = [
    {
      len: 1, offset: 0, d: {
        "0": "0：探头A关",
        "1": "1：探头A开"
      }
    },
    {
      len: 1, offset: 1, d: {
        "0": "0：探头B关",
        "1": "1：探头B开"
      }
    },
    {
      len: 1, offset: 2, d: {
        "0": "0：探头A地面模式",
        "1": "1：探头A科学模式（2048nT量程）"
      }
    },
    {
      len: 1, offset: 3, d: {
        "0": "0：探头B地面模式",
        "1": "1：探头B科学模式（2048nT量程）"
      }
    },
    {
      len: 2, offset: 4, d: {
        "00": "00b：1Hz采样率",
        "01": "01b：10Hz采样率",
        "10": "10b：128Hz采样率"
      }
    },
    {
      len: 1, offset: 6, d: {
        "0": "0：主份FPGA上电",
        "1": "1：备份FPGA上电"
      }
    },
    {
      len: 1, offset: 7, d: {
        "0": "主份3.3V上电",
        "1": "备份3.3V上电"
      }
    },
    {
      len: 1, offset: 8, d: {
        "0": "主份模拟电路接探头A",
        "1": "备份模拟电路接探头A"
      }
    },
    {
      len: 1, offset: 9, d: {
        "0": "数据未压缩",
        "1": "数据压缩"
      }
    },
    {len: 2, offset: 10, d: {}}
  ]

  function convertStatus(v) {
    let sBin = Number(v).toString(2).padStart(12, 0)
    return ST.slice(0, -1).map(v => {
      return v.d[sBin.slice(v.offset, v.offset + v.len)]
    }).join('<br>')
  }

  async function msg(e) {
    let d = JSON.parse(e.data)
    if (d.task) {
      let args = parseTask(d.task)
      this.task = d.task + '/.h5'
      $('#r-task').html('任务:' + args.label)
      return
    }
    // d = d.info
    // let cdata = d.data;
    // mm = [1, 1 / 10, 1 / 128][(d.zt >> 6) & 0b11] * 1000
    // t0 = new Date(d.time).getTime()
    // x = cdata[0][0].map((v, i) => {
    //     return [t0 + mm * i, cdata[0][0][i], cdata[1][0][i], cdata[2][0][i], cdata[0][1][i], cdata[1][1][i], cdata[2][1][i]]
    //   }
    // );
    // x = new Float64Array(x.flat())
    // async def bindata(request, raw, **kw):
    // t = request.args.t
    // offset = int(request.args.offset)
    // size = int(request.args.size)
    let [offset, size] = d.frm;
    let bufr = await fetch(`/-/omso.bin?t=${page.cur_task}&offset=${offset}&size=${size}`).then(v => v.arrayBuffer())
    let data = new Float64Array(bufr)
    charts.forEach(c => {
      c.setOption({series: {data: data}})
    })
    set_frmInfo(d)
  }

  function set_frmInfo(d) {
    $INFO.html(`
          <tr>
            <th>同步头</th>
            <td>${d.syn ? ("0x" + Number(d.syn).toString(16).padStart(4, 0)) : undefined}</td>
          </tr>
          <tr>
            <th>帧计数</th>
            <td>${d.cnt}</td>
          </tr>
          <tr>
            <th>时间码（探头AB第0组数据产生时间）</th>
            <td>${d.time}</td>
          </tr>
          <tr>
            <th>磁强计3.3V电压</th>
            <td>${d.u}</td>
          </tr>
          <tr>
            <th title="【探头A状态、探头B状态】">磁强计工作状态</th>
            <td style="font-size: 12px">${convertStatus(d.zt)}</td>
          </tr>
          <tr>
            <th>磁强计探头温度A</th>
            <td>${d.T_A}</td>
          </tr>
          <tr>
            <th>磁强计探头温度B</th>
            <td>${d.T_B}</td>
          </tr>
          <tr>
            <th>磁强计指令接收计数</th>
            <td>${d.zl_cnt}</td>
          </tr>
          <tr>
            <th>磁强计最后指令号</th>
            <td>${d.zl}</td>
          </tr>
          <tr>
            <th>磁强计伸杆脉冲计数</th>
            <td>${d.mc_cnt}</td>
          </tr>
          <tr>
            <th>磁强计探头相位</th>
            <td>${d.ttxw}</td>
          </tr>
          <tr>
            <th>磁强计信号处理单元模拟电路温度</th>
            <td>${d.T_dl}</td>
          </tr>
          <tr>
            <th>磁强计定标线圈温度</th>
            <td>${d.T_xq}</td>
          </tr>
          <tr>
            <th>串口通讯错误计数</th>
            <td>${d.w_cnt}</td>
          </tr>
          <tr>
            <th>串口通讯错误类型</th>
            <td>${d.w_type}</td>
          </tr>
    `)
  }

  function realtime() {
    pg.real()
    console.log('AMAG.REALTIME', $STATION)
  }

  function history() {
    $REAL_FLAG = false
    pg.history()
    console.log('amag.history', $STATION)
  }


  var REG_TSK = /(?<s>\/.*)\/(?<st>.+?)\/(?<orb>(?<day>(?<y>20\d{2})(?<m>\d{2})(?<d>\d{2})).*?)\//

  function parseTask(v) {
    let grp = REG_TSK.exec(v).groups
    grp.label = grp.orb + '/' + grp.st
    return grp
  }
</script>
</html>